Skip to content

Conversation

@przemkaczmarek
Copy link
Collaborator

🔧 Type of changes

  • new bid adapter

✨ What's the context?

#4198

@przemkaczmarek przemkaczmarek self-assigned this Oct 2, 2025
@osulzhenko osulzhenko linked an issue Oct 3, 2025 that may be closed by this pull request
- video
- native
supported-vendors: []
vendor-id: 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1133

- banner
- video
- native
supported-vendors: []
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leave it just as supported-vendors:

Comment on lines 31 to 33
BidderDeps nativeryBidderDeps(BidderConfigurationProperties nativeryConfigurationProperties,
@NotBlank @Value("${external-url}") String externalUrl,
JacksonMapper mapper) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please format

return mapper.mapper().convertValue(root, ExtRequest.class);
}

private boolean isAmpRequest(BidRequest request) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix the methods order

for (Imp imp : request.getImp()) {
try {
final ExtImpNativery extImp = parseImpExt(imp);
if (widgetId == null && extImp != null && StringUtils.isNotBlank(extImp.getWidgetId())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extImp cannot be null at this stage

final BidRequest singleImpRequest = request.toBuilder()
.imp(Collections.singletonList(imp))
.ext(updatedExt)
.cur(Collections.singletonList(DEFAULT_CURRENCY))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this change needed? I don't this in the Go version

Comment on lines 141 to 148
if (httpCall.getResponse() != null && httpCall.getResponse().getStatusCode() == 204) {
final MultiMap headers = httpCall.getResponse().getHeaders();
final String nativeryErr = headers != null ? headers.get(NATIVERY_ERROR_HEADER) : null;
if (StringUtils.isNotBlank(nativeryErr)) {
return Result.withError(BidderError.badInput("Nativery Error: " + nativeryErr + "."));
}
return Result.withError(BidderError.badServerResponse("No Content"));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this isn't going to work because the 204 status code is check before calling makeBids in the core, so probably we won't support this weird error-header approach

@CTMBNara what do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Y, it won't work


private BidderBid resolveBidderBid(Bid bid, String currency, List<BidderError> errors) {
try {
final ObjectNode nativeryExt = extractNativeryExt(bid.getExt());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's create a separate BidExtNativery object and deserialize with the object mapper, because that manual conversion feels bad

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^^

Comment on lines 193 to 202
private ObjectNode extractNativeryExt(ObjectNode bidExt) {
if (bidExt == null) {
throw new PreBidException("missing bid.ext");
}
final JsonNode node = bidExt.get("nativery");
if (!(node instanceof ObjectNode nativeryNode)) {
throw new PreBidException("missing bid.ext.nativery");
}
return nativeryNode;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace with a simple Optional chain

return Result.of(Collections.emptyList(), errors);
}

// 🟢 Zmienione — zamieniamy ExtRequest na ObjectNode
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove the comments

}

if (validImps.isEmpty()) {
return Result.of(Collections.emptyList(), errors);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Result.withErrors(errors)

Comment on lines 86 to 88
final ObjectNode originalExt = request.getExt() != null
? mapper.mapper().convertValue(request.getExt(), ObjectNode.class)
: null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not necessary to serialize ExtRequest object into the ObjectNode, because ExtRequest is a FlexibleExtension

Comment on lines 117 to 119
final ExtPrebid<?, ExtImpNativery> ext =
mapper.mapper().convertValue(imp.getExt(), NATIVERY_EXT_TYPE_REFERENCE);
return ext != null ? ext.getBidder() : null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imp.ext can't be null at this stage, so it can't be deserialized into null

Comment on lines 125 to 138
private ExtRequest buildRequestExtWithNativery(ObjectNode originalExt, boolean isAmp, String widgetId) {
final ObjectNode root = originalExt != null
? originalExt.deepCopy()
: mapper.mapper().createObjectNode();

final ObjectNode nativeryNode = root.with("nativery");

nativeryNode.put("isAmp", isAmp);
if (widgetId != null) {
nativeryNode.put("widgetId", widgetId);
}

return mapper.mapper().convertValue(root, ExtRequest.class);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use ExtRequest and FlexibleExtension capabilities


private BidderBid resolveBidderBid(Bid bid, String currency, List<BidderError> errors) {
try {
final ObjectNode nativeryExt = extractNativeryExt(bid.getExt());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^^

Comment on lines 141 to 148
if (httpCall.getResponse() != null && httpCall.getResponse().getStatusCode() == 204) {
final MultiMap headers = httpCall.getResponse().getHeaders();
final String nativeryErr = headers != null ? headers.get(NATIVERY_ERROR_HEADER) : null;
if (StringUtils.isNotBlank(nativeryErr)) {
return Result.withError(BidderError.badInput("Nativery Error: " + nativeryErr + "."));
}
return Result.withError(BidderError.badServerResponse("No Content"));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Y, it won't work

Comment on lines +141 to +144
final var response = httpCall.getResponse();
if (response == null || StringUtils.isBlank(response.getBody())) {
return Result.withError(BidderError.badServerResponse("Empty response"));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this check

Comment on lines +178 to +179
final List<String> advDomains = ListUtils.defaultIfNull(
nativeryExt.getBidAdvDomains(), Collections.emptyList());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I made a typo and recommended the wrong method. Use ListUtils.emptyIfNull() directly.

Comment on lines +215 to +222
private static String mediaTypeString(BidType type) {
return switch (type) {
case banner -> type.getName();
case video -> type.getName();
case xNative -> type.getName();
default -> throw new IllegalStateException("Unexpected value: " + type.getName());
};
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this method and use type.getName instead

Comment on lines +227 to +228
final List<String> safeAdvDomains = Optional.ofNullable(advDomains)
.orElse(Collections.emptyList());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

advDomains can't be null

Comment on lines +11 to +15
@JsonProperty("bid_ad_media_type")
String bidAdMediaType;

@JsonProperty("bid_adv_domains")
List<String> bidAdvDomains;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for @JsonProperty. Our objectMapper uses snake-case by default

Comment on lines +133 to +134
final ObjectNode extNode = mapper.createObjectNode();
extNode.put("accountId", "acc-123");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ObjectNode -> ExtRequest. You can add custom properties to it since it is a FlexibleExtension

Comment on lines +164 to +169
final ObjectNode extNode = mapper.createObjectNode();
final ObjectNode prebidNode = mapper.createObjectNode();
final ObjectNode serverNode = mapper.createObjectNode();
serverNode.put("endpoint", Endpoint.openrtb2_amp.value());
prebidNode.set("server", serverNode);
extNode.set("prebid", prebidNode);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Port PR from PBS-Go: New Adapter: Nativery

4 participants